/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "面/面.h"
#include <matXX.h>
#include "core/空间划分/球形八叉树.h"


void f_surface_计算自动权重(S_Mesh* me, const Mat44f& mat, S_骨架* 骨架, float32 封套延申长度) {
	uint32 num = me->f_get顶点数量();
	float32* 权重 = nullptr;// = f_buf_map板载缓存<float32>(me->m_骨骼权重);
	uint32* 骨骼ID = nullptr;// = f_buf_map板载缓存<uint32>(me->m_顶点对应骨骼ID);

	uint32 权重层数 = 4;
	uint32 骨头数量 = 骨架->m_骨头数量;
	Mat44f* boneMat = f_buf_Mat44_ptr(骨架->m_骨骼变换);
	float32* boneLen = f_buf_F32_ptr(骨架->m_骨骼长度);
	
	std::vector<vec3> 变换后顶点(num);
	vec3* vert_p = 变换后顶点.data();
	std::vector<vec3> 变换后法线(num);
	vec3* normal_p = 变换后法线.data();

	if (num > 2048) {

	}
	else {

	}

	vec3 bounding = f_surface_get包围盒大小(me, mat);
	auto* tree = f_空间划分_create球形八叉树(DEF_Max(DEF_Max(bounding.x, bounding.y), bounding.z));

	


	//auto v = me->f_map顶点();
	//auto 索引 = me->f_map索引();

	for (uint32 i = 0; i < num; ++i) {
		for (uint32 j = 0; j < 权重层数; ++j) {
			uint32 offset = j * num + i;
			权重[offset] = -1;
		}
		

		vec3 vert;
		vec3 normal;
		switch (*me->m_顶点配置Flags)
		{
		case E_顶点组合标志::e_坐标:
			break;
		case E_顶点组合标志::e_坐标_法线:
			break;
		case E_顶点组合标志::e_坐标_法线_UV: {
			//vert_p[i] = mat * ((S_VNT1*)v.point)[i].vert;
			vert_p[i] = mat * f_buf_VNT_ptr(*me->m_顶点)[i].vert;
			//normal = mat * ((S_VNT1*)v.point)[i].normal;
			normal = mat * f_buf_VNT_ptr(*me->m_顶点)[i].normal;
			break;
		}
		case E_顶点组合标志::e_坐标_颜色:
			break;
		case E_顶点组合标志::e_坐标_UV:
			break;
		default:
			break;
		}

		float32 minDir = -1;
		uint32 boneID = -1;
		for (uint32 k = 0; k < 骨头数量; ++k) {
			vec3 bs = boneMat[k] * vec3{};
			vec3 be = boneMat[k] * vec3{0, 0, boneLen[k]};
			vec3 dir = vec_normalize(be - bs);

			float32 骨头一半长度 = boneLen[k] * 0.5;
			vec3 中点 = bs + dir * 骨头一半长度;

			float32 距中心点距离 = vec_len(中点 - vert_p[i]);
			float32 大圈权重 = 1.0 - DEF_Min(距中心点距离 / (骨头一半长度 + boneLen[k] * 封套延申长度), 1.0);
			
			float32 d = f_graph_点到直线距离(bs, dir, vert_p[i]);
			float32 距离骨骼方向权重 = 大圈权重 * (1.0 - DEF_Min(d, 1));

			
			//d = 距离骨骼方向权重;
			if (距离骨骼方向权重 > minDir) {
				minDir = 距离骨骼方向权重;
				boneID = k;
			}

			if (距离骨骼方向权重 > 2) {
				距离骨骼方向权重 = 0;
			}
		}

		//minDir *= 0.1;
		uint8 最小层 = 0;
		float32 temp最小权重 = -1;
		for (uint32 j = 0; j < 权重层数; ++j) {
			uint32 offset = j * num + i;
			if (temp最小权重 > 权重[offset]) {
				temp最小权重 = 权重[offset];
				最小层 = j;
			}
		}
		
		权重[最小层 * num + i] = minDir;
		
		if (boneID != -1) {
			骨骼ID[i] |= (boneID << (最小层*8));
		}
	}
	


	for (uint32 i = 0; i < num; ++i) {
		for (uint32 k = 0; k < 骨头数量; ++k) {
			vec3 bs = boneMat[k] * vec3{};
			vec3 be = boneMat[k] * vec3{ 0, 0, boneLen[k] };
			vec3 dir = vec_normalize(be - bs);


			vec3 点到骨骼朝向 = f_graph_计算点到直线垂足坐标(bs, dir, vert_p[i]);
			点到骨骼朝向 = vec_normalize(点到骨骼朝向 - vert_p[i]);
			float32 顶点法线垂直骨骼强度 = vec_dot(点到骨骼朝向, normal_p[i]);

		}
	}


	//me->f_unmap顶点();
	//f_buf_unmap板载缓存(me->m_蒙皮权重);
}

void f_surface_构建顶点相连面索引(S_Mesh* me, std::vector<std::vector<uint32>>& 顶点相邻面) {
	uint32 顶点数量   = me->f_get顶点数量();
	uint32 索引数量   = me->m_索引->m_Mem.m_大小 / 3;
	const uvec3* p索引 = (uvec3*)f_buf_UI32_ptr(*me->m_索引);

	顶点相邻面.resize(顶点数量);
	auto* 顶点相邻面指针 = 顶点相邻面.data();
#pragma omp parallel for 
	for (int32 i = 0; i < 顶点数量; ++i) {
		顶点相邻面指针[i].reserve(20);
	}

	for (uint32 面ID = 0; 面ID < 索引数量; ++面ID) {
		顶点相邻面指针[p索引[面ID].x].emplace_back(面ID);
		顶点相邻面指针[p索引[面ID].y].emplace_back(面ID);
		顶点相邻面指针[p索引[面ID].z].emplace_back(面ID);
	}
}

void f_surface_计算面平滑法线(S_Mesh* me, const std::vector<std::vector<uint32>>& 顶点相邻面) {
	uint32 顶点数量   = me->m_顶点->m_Mem.m_大小;
	const uvec3* p索引 = (uvec3*)f_buf_UI32_ptr(*me->m_索引);


	auto* 顶点相邻面指针 = 顶点相邻面.data();

	switch (*me->m_顶点配置Flags) {
	case E_顶点组合标志::e_坐标_法线_UV: {
		S_VNT1* p顶点 = f_buf_VNT_ptr(*me->m_顶点);

#pragma omp parallel for
		for (int32 i = 0; i < 顶点数量; ++i) {
			auto* 面索引 = 顶点相邻面指针[i].data();
			uint32 面索引数量 = 顶点相邻面指针[i].size();

			vec3 法线 = {};
//#pragma omp parallel for num_threads(4)
			for (int32 j = 0; j < 面索引数量; ++j) {
				uvec3 trangle = p索引[面索引[j]];
				if (trangle.x >= 顶点数量 || trangle.x >= 顶点数量 || trangle.x >= 顶点数量) {
					std::cout<<"顶点索引越界"<<std::endl;
					continue;
				}
				法线 += f_surface_从面计算法线(p顶点[trangle.x].vert, p顶点[trangle.y].vert, p顶点[trangle.z].vert);
			}

			p顶点[i].normal = vec_normalize(法线);
		}
		break;
	}
	case E_顶点组合标志::e_坐标_法线: {
		S_VN* p顶点 = f_buf_VN_ptr(*me->m_顶点);

#pragma omp parallel for
		for (int32 i = 0; i < 顶点数量; ++i) {
			auto* 面索引 = 顶点相邻面指针[i].data();
			uint32 面索引数量 = 顶点相邻面指针[i].size();

			vec3 法线 = {};
			for (int32 j = 0; j < 面索引数量; ++j) {
				uvec3 trangle = p索引[面索引[j]];
				法线 += f_surface_从面计算法线(p顶点[trangle.x].vert, p顶点[trangle.y].vert, p顶点[trangle.z].vert);
			}

			p顶点[i].normal = vec_normalize(法线);
		}
		break;
	}
	default:
		break;
	}

}

void f_surface_应用变换(S_Mesh* me, const Mat44f& mat) {
	//auto 顶点 = me->f_map顶点();
	//uint32 顶点数量   = 顶点.count;
	uint32 顶点数量   = me->m_顶点->m_Mem.m_大小;

	switch (*(me->m_顶点配置Flags)) {
	case E_顶点组合标志::e_坐标_法线_UV: {
		//S_VNT1* p顶点 = (S_VNT1*)顶点.point;
		S_VNT1* p顶点 = f_buf_VNT_ptr(*me->m_顶点);

		auto rotMat = f_mat44_to_33(mat);
		mat33_normalize(rotMat);

		for (int32 i = 0; i < 顶点数量; ++i) {
			p顶点[i].vert = mat * p顶点[i].vert;
			p顶点[i].normal = rotMat * p顶点[i].normal;
		}

		break;
	}
	case E_顶点组合标志::e_坐标_颜色: {
		//S_VC* p顶点 = (S_VC*)顶点.point;
		S_VC* p顶点 = f_buf_VC_ptr(*me->m_顶点);

		for (int32 i = 0; i < 顶点数量; ++i) {
			p顶点[i].vert = mat * p顶点[i].vert;
		}

		break;
	}
	}

	//me->f_unmap顶点();
}

vec3 f_surface_变换包围盒(vec3 size, const Mat44f& mat) {
	vec3 v[] = { 
	    {},
		{size.x, 0, 0},
		{0, size.y, 0},
		{0, 0, size.z},

		{size.x, size.y, 0},
		{size.x, 0, size.z},
		{0, size.y, size.z},

		{size.x, size.y, size.z},
	};

	for (uint32 i = 0; i < 8; ++i) {
		v[i] = mat * v[i];
	}

	vec3 最小={1000000000,1000000000,1000000000};
	vec3 最大={-1000000000,-1000000000,-1000000000};
	for (uint32 i = 0; i < 8; ++i) {
		最小 = vec_Min(v[i], 最小);
		最大 = vec_Max(v[i], 最大);
	}

	return 最大 - 最小;
}









